﻿using System;
using System.IO;
using System.Text;

namespace EditMode
{
    public static class BinaryHelper
    {
        public static void Seek(this BinaryReader binaryReader, long position, SeekOrigin seekOrigin = SeekOrigin.Begin)
        {
            if (position >= 0 && position <= binaryReader.GetLength())
            {
                binaryReader.BaseStream.Seek(position, seekOrigin);
            }
        }

        public static long GetPosition(this BinaryReader binaryReader)
        {
            return binaryReader.BaseStream.Position;
        }

        public static long GetLength(this BinaryReader binaryReader)
        {
            return binaryReader.BaseStream.Length;
        }

        public static int GetStringLength(this BinaryReader binaryReader)
        {
            long pos = binaryReader.GetPosition();
            for (int stringLength = 0; true; stringLength++)
            {
                if (binaryReader.GetPosition() >= binaryReader.GetLength() || binaryReader.ReadByte() == 0x00)
                {
                    binaryReader.Seek(pos);
                    return stringLength;
                }
            }
        }

        public static string ReadAsciiString(this BinaryReader binaryReader)
        {
            int stringLength = binaryReader.GetStringLength();
            byte[] charBuffer = binaryReader.ReadBytes(stringLength);
            return Encoding.ASCII.GetString(charBuffer);
        }

        public static (int pointer, int value) ReadInt32Ptr(this BinaryReader binaryReader, SeekOrigin seekOrigin = SeekOrigin.Begin)
        {
            long position = binaryReader.GetPosition();
            int pointer = binaryReader.ReadInt32();

            binaryReader.Seek(pointer, seekOrigin);
            int value = binaryReader.ReadInt32();

            binaryReader.Seek(position + 4, SeekOrigin.Begin);
            return (pointer, value);
        }

        public static (int pointer, string value) ReadStringPtr(this BinaryReader binaryReader, SeekOrigin seekOrigin = SeekOrigin.Begin)
        {
            long position = binaryReader.GetPosition();
            int pointer = binaryReader.ReadInt32();

            binaryReader.Seek(pointer, seekOrigin);
            string str = binaryReader.ReadAsciiString();

            binaryReader.Seek(position + 4, SeekOrigin.Begin);
            return (pointer, str);
        }

        public static (float x, float y) ReadVector2(this BinaryReader binaryReader)
        {
            return (binaryReader.ReadSingle(), binaryReader.ReadSingle());
        }

        public static short ReadStaticInt16(this BinaryReader binaryReader)
        {
            short int16 = binaryReader.ReadInt16();
            binaryReader.Seek(-2, SeekOrigin.Current);
            return int16;
        }

        public static int ReadStaticInt32(this BinaryReader binaryReader)
        {
            int int32 = binaryReader.ReadInt32();
            binaryReader.Seek(-4, SeekOrigin.Current);
            return int32;
        }

        public static long ReadStaticInt64(this BinaryReader binaryReader)
        {
            long int64 = binaryReader.ReadInt64();
            binaryReader.Seek(-8, SeekOrigin.Current);
            return int64;
        }

        public static float ReadStaticSingle(this BinaryReader binaryReader)
        {
            float single = binaryReader.ReadSingle();
            binaryReader.Seek(-4, SeekOrigin.Current);
            return single;
        }

        public static double ReadStaticDouble(this BinaryReader binaryReader)
        {
            double @double = binaryReader.ReadDouble();
            binaryReader.Seek(-8, SeekOrigin.Current);
            return @double;
        }

        public static byte ReadStaticByte(this BinaryReader binaryReader)
        {
            byte @byte = binaryReader.ReadByte();
            binaryReader.Seek(-1, SeekOrigin.Current);
            return @byte;
        }

        public static byte[] ReadStaticBytes(this BinaryReader binaryReader, int count)
        {
            byte[] bytes = binaryReader.ReadBytes(count);
            binaryReader.Seek(-count, SeekOrigin.Current);
            return bytes;
        }

        public static string ReadFormattedBytes(this BinaryReader binaryReader, int count)
        {
            return BitConverter.ToString(binaryReader.ReadBytes(count));
        }

        public static string ReadFormattedBytes(this BinaryReader binaryReader, int count, int chunks)
        {
            string[] strings = new string[chunks];
            for (int i = 0; i < chunks; i++)
                strings[i] = binaryReader.ReadFormattedBytes(count);
            return string.Join(" ", strings);
        }
    }
}
